#include "CruiseControl.h";
/*
--------------------------interne structs en variabele--------------------------
*/
//maakt een STD singleton, dit kan omdat alle cruise control objecten dezelfde STD hebben
//deze wordt opgeruimt bij de methode afsluiten.
static STD* cruiseSTD=NULL;

//deze informatie moet worden doorgegeven aan de opdracht van de state
struct stateData{
	cruiseControl* cc; //hij moet de snelheid kunnen aanpassen
	int huidigeSnelheid; //hij moet wel de huidige snelheid weten om er iets mee te kunnen
};
typedef struct stateData stateData;
/*
--------------------------interne opdrachten--------------------------
*/

//deze actie wordt uitgevoerd als het systeem inactief dient te worden
void afslaan(void* arg){
	outputInvoer oI; //maak een output invoer aan
	stateData *si = (stateData*)arg;//de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc;//in de state data staat een cruiseControl waarop we een bewerking willen doen 

	cruise->ingesteldeSnelheid = 0;
	//de ingestelde snelheid wordt leesbaar gemaakt voor de output
	//beide zijn 0 omdat er dan niet bijgesteld hoeft te worden (het verschil tussen 0 en 0 is altijd 0)
	//dit kon ook met andere getallen maar er is voor het gemak gekozen voor 0
	oI.ingesteldeSnelheid = 0;
	oI.huidigeSnelheid = 0;
	oI.stat = cruise->status;
	put_mailBox(&(*cruise).out.Todo, &oI); //zet wat gedaan moet worden in de mailbox van out
}

//zet de snelheid vast op de huidige snelheid
void snelheidVastzetten(void* arg){
	stateData *si = (stateData*)arg;//de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc;//in de state data staat een cruiseControl waarop we een bewerking willen doen 
	(*cruise).ingesteldeSnelheid = (*si).huidigeSnelheid; //zet de huidige snelheid neer als ingestelde snelheid van de cruise control
}

//de standaard taak die de snelheid bijsteld
void snelheidControleren(void* arg){
	outputInvoer oI; //maak 
	stateData *si = (stateData*)arg;//de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc;//in de state data staat een cruiseControl waarop we een bewerking willen doen 
	
	//de ingestelde snelheid wordt leesbaar gemaakt voor de output
	oI.ingesteldeSnelheid = (*cruise).ingesteldeSnelheid; 
	oI.huidigeSnelheid = (*si).huidigeSnelheid;
	oI.stat = cruise->status;
	put_mailBox(&(*cruise).out.Todo, &oI); //zet wat gedaan moet worden in de mailbox van out
}

//als op de snelheidVerhogen knop gedrukt wordt
void snelheidOmhoog(void* arg){
	stateData *si = (stateData*) arg;//de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc;//in de state data staat een cruiseControl waarop we een bewerking willen doen 
	(*cruise).ingesteldeSnelheid = (*cruise).ingesteldeSnelheid +5;//de snelheid die ingesteld is moet met 5 omhoog
	snelheidControleren(&(*si)); //na het hebben ingesteld moet de normale controle gedaan worden
}

//als op de snelheidVerlagen knop gedrukt wordt
void snelheidOmlaag(void* arg){
	stateData *si = (stateData*) arg; //de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc; //in de state data staat een cruiseControl waarop we een bewerking willen doen 
	(*cruise).ingesteldeSnelheid = (*cruise).ingesteldeSnelheid - 5; //de snelheid die ingesteld is moet met 5 omlaag
	snelheidControleren(&(*si)); //na het hebben ingesteld moet de normale controle gedaan worden
}

//als op de Pauze knop gedrukt wordt
void pauzeren(void* arg)
{
	outputInvoer oI; //maak de invoer voor output
	stateData *si = (stateData*)arg;//de data die werd meegegeven is van het type stateData
	cruiseControl *cruise = (*si).cc;//in de state data staat een cruiseControl waarop we een bewerking willen doen 

	//de ingestelde snelheid wordt leesbaar gemaakt voor de output
	oI.ingesteldeSnelheid = cruise->ingesteldeSnelheid;
	oI.huidigeSnelheid = cruise->ingesteldeSnelheid;
	//de huidige status wordt meegegeven
	oI.stat = cruise->status;
	put_mailBox(&(*cruise).out.Todo, &oI); //zet wat gedaan moet worden in de mailbox van out
}

void nietsDoen(void* arg){
	//wat zou die nou doen?
}

//als er weer op pauze gedrukt wordt
void resume(void* arg){
	snelheidControleren(arg); //de normale acties dienen verder gevolgd te worden
}

//deze opdracht maakt het State Transition Diagram en zorgt ervoor dat deze alle statussen en overgangen bevat
void STDMaken(cruiseControl *cc)
{
	if(cruiseSTD==NULL) //controleer of het STD nog altijd NULL is
	{	//indien de STD NULL is moet deze gevuld worden met data
		//Reserveer geheugen
		cruiseSTD=(STD*)malloc(sizeof(STD));
		//maak STD
		create_STD(cruiseSTD,3,nietsDoen); //indien een niet legale actie wordt uitgevoerd moet het systeem niets doen
		//Alle mogelijke overgangen toevoegen
		addTransition_STD(cruiseSTD, inactief, activatieknopIndrukken, actief, snelheidVastzetten); //de snelheid moet worden vastgezet
		addTransition_STD(cruiseSTD, actief, activatieknopIndrukken, inactief, afslaan); //het systeem moet niets meer doen
		addTransition_STD(cruiseSTD, actief, PedaalIndrukken, inactief, afslaan); //ook hier moet het systeem niets doen
		addTransition_STD(cruiseSTD, pauze, Pauzeren, actief, resume); //hier moet het systeem verder gaan met het regelen
		addTransition_STD(cruiseSTD, actief, Pauzeren, pauze, pauzeren); //vanaf hier moet het systeem wachten totdat weer op pauze gedrukt wordt
		addTransition_STD(cruiseSTD, actief, Snelheidverhogen, actief, snelheidOmhoog); //de snelheid moet verhoogd worden
		addTransition_STD(cruiseSTD, actief, Snelheidverlagen, actief, snelheidOmlaag); //de snelheid moet verlaagd worden
		addTransition_STD(cruiseSTD, actief, SnelheidControleren, actief, snelheidControleren); //de snelheid moet gecontroleerd worden
	}
	//de meegegeven Cruise control moet altijd in de begin status gebracht worden
	(*cc).status = inactief; //bij systeem start is de status van de cruise control inactief
}

/*
--------------------------openbare opdrachten--------------------------
*/

//geeft de mailbox van de sensorInput
mailBox* Get_sensorInput(cruiseControl* cc)
{
	return GiveInput(&((*cc).sens));
}

//geeft de mailbox van de outputOut
mailBox* Get_outputOut(cruiseControl* cc)
{
	return GiveOutputOut(&((*cc).out));
}

//initialiseert de cruise control en zijn onderdelen
void CruiseInit(cruiseControl* cc)
{
	(*cc).taak = (task*)malloc(sizeof(task)); //maak ruimte voor de taak
	sensorInit(&(*cc).sens); //start de sensor init
	outputInit(&(*cc).out); //start de output init
	(*cc).ingesteldeSnelheid = 0; //de ingestelde snelheid is standaard 0
	STDMaken(cc);
}

//zorgt ervoor dat het systeem zijn werk kan doen
unsigned __stdcall autostart(void* arg){
	task* t = (task*) arg; //haal de taak op
	SensorUitvoer uit; //maak een tijdelijke opslag voor de mail uit de mailbox van de sensor
	stateData data; //maak een opslag waarin state data kan worden gezet
	actionType aT; //maak een actionType, aan de hand hiervan wordt een taak uitgevoerd
	cruiseControl *cc = (cruiseControl *)getArgument_task(t); //haal de parameter op
	create_task((*cc).sens.taak, inputStart, &(*cc).sens, sizeof(sensor), 0); //start de sensor
	create_task((*cc).out.taak, outputStart, &(*cc).out, sizeof(output), 0); //start de ouput
	while(!isTerminated_task(t)) //zolang de taak niet be-eindigd is
	{
		get_mailBox(&(*cc).sens.sensorOutput,&uit); //haal de data op uit de mailbox
		data.cc = cc; //de betreffende cruise control moet bekent zijn bij de state data
		data.huidigeSnelheid = uit.snelheid; //de snelheid moet op de goede plaats in de state data worden gezet
		
		//de toestand := de opgezochte status van (de Huidige STD, aan de hand van de huidige status, door de volgende actie, moet deze actie plaatsvinden)
		(*cc).status = (Status)lookUp_STD(cruiseSTD,(*cc).status,uit.actie,&aT);
		aT(&data); //stuur naar deze opdracht de verzamelde data die van belang is		
	}
	return 0;
}

//verwijdert de taak van cruise control
void CruiseDelete(cruiseControl* cc)
{
	delete((*cc).taak);
	sensorDelete(&(*cc).sens);
	outputDelete(&(*cc).out);
}

//deze taak verwijdert het STD
void Afsluiten(){
	delete_STD(cruiseSTD);
}